<template>
  <van-nav-bar title="以爱之名-拼图" left-text="返回" left-arrow @click-left="$router.back" />
  <div class="box">
    <transition-group name="cell" tag="div" class="container">
      <div
        @click.prevent="clickBlock(index)"
        v-for="(puzzle, index) in puzzles"
        :key="puzzle"
        class="cell"
        :class="{
          cells: puzzle == 0
        }"
        :style="{
          opacity: puzzle != 0 ? 1 : isFinish ? 1 : 0
        }"
      >
        <img :src="imgs[puzzle]" style="width: 100%" />
      </div>
    </transition-group>

    <div style="text-align: center; margin-top: 10px">总用时 {{ timeText }}</div>
    <div class="btns">
      <van-button type="primary" @click="start()">重来</van-button>
      <van-button type="primary" @click="startOrPause()" v-if="!isFinish">
        {{ pause ? '开始' : '暂停' }}
      </van-button>
      <van-button type="primary" @click="aotoPlay()" v-if="!isFinish">自动</van-button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { showSuccessToast } from 'vant'
import useTimer from './timer'

const chunk = (input, size) => {
  return input.reduce((arr, item, idx) => {
    return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]]
  }, [])
}

// 求逆序奇偶性
function odevity(node) {
  var num = 0
  node.splice(node.indexOf('0'), 1)
  node.forEach(function (item, index) {
    for (var i = 0; i < index; i++) {
      if (node[i] != 0) {
        if (node[i] > item) {
          num++
        }
      }
    }
  })
  if (num % 2) {
    return 1
  } else {
    return 0
  }
}
// 是否可达
function canReach(originalNode, resultNode) {
  originalNode = originalNode.toString().split(',')
  resultNode = resultNode.toString().split(',')
  if (odevity(originalNode) === odevity(resultNode)) {
    return true
  } else {
    return false
  }
}

let imgs = {
  1: new URL('./img/1.gif', import.meta.url).href,
  2: new URL('./img/2.gif', import.meta.url).href,
  3: new URL('./img/3.gif', import.meta.url).href,
  4: new URL('./img/4.gif', import.meta.url).href,
  5: new URL('./img/5.gif', import.meta.url).href,
  6: new URL('./img/6.gif', import.meta.url).href,
  7: new URL('./img/7.gif', import.meta.url).href,
  8: new URL('./img/8.gif', import.meta.url).href,
  0: new URL('./img/9.gif', import.meta.url).href
}

let puzzles = ref([])
const getData = () => ({
  originalNode: chunk(puzzles.value, 3),
  // originalNode: [[1, 3, 2],[5, 8, 0],[7, 6, 4]],
  resultNode: [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 0]
  ]
})
// 打乱
function shuffle() {
  const length = puzzles.value.length
  let index = -1
  const lastIndex = length - 1
  const result = [...puzzles.value]
  while (++index < length) {
    const rand = index + Math.floor(Math.random() * (lastIndex - index + 1))
    const value = result[rand]
    result[rand] = result[index]
    result[index] = value
  }
  puzzles.value = result

  let Setting = getData()
  if (!canReach(Setting.originalNode, Setting.resultNode)) {
    shuffle()
  }
}

let { timeText, pauseTime, startTime, pause, startOrPause } = useTimer()

let isFinish = ref(false)

// 是否通过
function pass() {
  if (puzzles.value[8] === '0' || puzzles.value[8] === 0) {
    const newPuzzles = puzzles.value.slice(0, 8)
    const isPass = newPuzzles.every((e, i) => +e === i + 1)
    if (isPass) {
      isFinish.value = true
      pauseTime()
      showSuccessToast('完成，mua~')
    }
  }
}

// 点击方块
function clickBlock(index) {
  if (isFinish.value) {
    return
  }
  let curIndex = puzzles.value[index]
  let leftIndex = puzzles.value[index - 1]
  let rightIndex = puzzles.value[index + 1]
  let topIndex = puzzles.value[index - 3]
  let bottomIndex = puzzles.value[index + 3]

  let targetIndex
  if (leftIndex == 0 && index % 3) {
    targetIndex = index - 1
  } else if (rightIndex == 0 && 2 !== index % 3) {
    targetIndex = index + 1
  } else if (topIndex == 0) {
    targetIndex = index - 3
  } else if (bottomIndex == 0) {
    targetIndex = index + 3
  }
  if (targetIndex != null) {
    puzzles.value[targetIndex] = curIndex
    puzzles.value[index] = 0
  }
  pass()
}

function start() {
  isFinish.value = false
  puzzles.value = [1, 2, 3, 4, 5, 6, 7, 8, 0]
  shuffle()
  startTime(0)
}
onMounted(() => {
  start()
})

// 自动
function aotoPlay() {
  let Setting = getData()
  autoPuzzles(Setting).searchPath()
}
// 自己玩执行
function autoPuzzles(Setting) {
  let queueArr = [] //队列
  let hashObj = {} //hash
  let NodeObj = {} //记录节点
  let originalNode = Setting.originalNode //原始节点
  let originalNodeStr = originalNode.toString().split(',').join('')
  let resultNode = Setting.resultNode //结果节点
  let resultNodeStr = resultNode.toString().split(',').join('')
  let isFind = false
  let delay = 500

  return {
    // 寻找路径
    searchPath() {
      var _this = this
      queueArr.push(originalNode)
      hashObj[originalNodeStr] = originalNode
      while (!isFind) {
        if (!queueArr.length) {
          alert('没搜索到结果')
          return
        }
        let currentNode = queueArr.shift(),
          currentNodeStr = currentNode.toString().split(',').join('')
        if (resultNodeStr === currentNodeStr) {
          let path = []
          let pathLength = 0
          let resultPath = []
          for (let v = resultNodeStr; v != originalNodeStr; v = NodeObj[v]) {
            path.push(hashObj[v])
          }
          path.push(hashObj[originalNodeStr])
          pathLength = path.length
          for (let i = 0; i < pathLength; i++) {
            resultPath.push(path.pop())
          }
          setTimeout(function () {
            _this.returnStep(resultPath)
          }, 500)
          isFind = true
          return
        }
        // return;
        let result = this.getChildNodes(currentNode)
        result.forEach(function (item) {
          let itemStr = item.toString().split(',').join('')
          if (!hashObj[itemStr]) {
            queueArr.push(item)
            hashObj[itemStr] = item
            NodeObj[itemStr] = currentNodeStr
          }
        })
      }
    },
    // 返回步骤信息
    returnStep(path) {
      var _this = this
      path.forEach(function (item, index) {
        setTimeout(
          function (node) {
            _this.readerDom(node)
          }.bind(_this, item),
          index * delay
        )
      })
    },
    // 渲染dom
    readerDom(node) {
      let nodeArr = node.flat()
      puzzles.value = nodeArr
      pass()
    },
    // 获取子节点
    getChildNodes(currentNode) {
      if (!Array.isArray(currentNode)) return
      let target = {},
        direction = [],
        rowNum = currentNode.length,
        colNum = currentNode[0].length
      currentNode.forEach(function (item, i) {
        item.forEach(function (obj, k) {
          if (obj === 0 || obj === '0') {
            target = { x: k, y: i }
          }
        })
      })
      direction = this.getDirection(target, rowNum, colNum)
      return this.changePos(currentNode, target, direction)
    },
    // 获取方向
    getDirection(target, rowNum, colNum) {
      let direction = []
      if (!target.x) {
        direction.push('right')
      } else if (target.x === colNum - 1) {
        direction.push('left')
      } else {
        direction = direction.concat(['left', 'right'])
      }

      if (!target.y) {
        direction.push('down')
      } else if (target.y === rowNum - 1) {
        direction.push('up')
      } else {
        direction = direction.concat(['down', 'up'])
      }
      return direction
    },
    // 改变位置
    changePos(node, target, direction) {
      if (direction.length) {
        let childNodesArr = []
        direction.forEach(function (item) {
          let temp
          let _node = JSON.parse(JSON.stringify(node))
          switch (item) {
            case 'left':
              temp = _node[target.y][target.x]
              _node[target.y][target.x] = _node[target.y][target.x - 1]
              _node[target.y][target.x - 1] = temp
              break
            case 'right':
              temp = _node[target.y][target.x]
              _node[target.y][target.x] = _node[target.y][target.x + 1]
              _node[target.y][target.x + 1] = temp
              break
            case 'down':
              temp = _node[target.y][target.x]
              _node[target.y][target.x] = _node[target.y + 1][target.x]
              _node[target.y + 1][target.x] = temp
              break
            case 'up':
              temp = _node[target.y][target.x]
              _node[target.y][target.x] = _node[target.y - 1][target.x]
              _node[target.y - 1][target.x] = temp
              break
          }
          childNodesArr.push(_node)
        })
        return childNodesArr
      }
    }
  }
}
</script>

<style scoped>
.box {
  position: absolute;

  position: absolute;
  top: 50px;
  left: 50%;
  transform: translateX(-50%);
}

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  width: 302px;
  margin-top: 10px;
  border: 1px solid #ccc;
}
.cell {
  width: 100px;
  height: 100px;
}
.cells {
  pointer-events: none;
  opacity: 0;
  transition: 0.7s cubic-bezier(1, 0, 1, 0) !important;
}
.cell-move {
  transition: transform 0.5s;
}

.btns {
  margin-top: 20px;
  display: flex;
  justify-content: space-around;
}
</style>
